home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / LISP Related / Generalized LISP / Glisp 1.2 / Mlisp dialect / Mlisp.glisp < prev    next >
Encoding:
Text File  |  1990-08-19  |  13.2 KB  |  496 lines  |  [TEXT/CCL ]

  1.  
  2. ~---------------------------------------------------------------------------------------~
  3. ~                Rules for Mlisp (Meta Lisp)                ~
  4. ~---------------------------------------------------------------------------------------~
  5.  
  6. -define language Mlisp-
  7.  
  8.  
  9. -Lisp-
  10.  
  11. `(export '(mlispProgram mlispFunction reparseMlisp) :glisp)
  12.  
  13.  
  14. -Plisp-
  15.  
  16. glispLanguage (add rule) =
  17.     ~ add the Mlisp dialect to "Generalized Lisp"
  18.  
  19.     '-  Mlisp  '-  <mlispProgram>:p  ->  :p;
  20.  
  21.  
  22. mlispProgram =
  23.     ~ an Mlisp program is a sequence of expressions each terminated by a semicolon
  24.  
  25.     <sourceLanguage Mlisp>  [ <expression>:e  ';  <flush> ]*  ->  :e;
  26.  
  27.  
  28. expression =
  29.     ~ an expression is one or more basic expressions separated by the word "also".
  30.     ~ this clumps multiple expressions into one (progn ...) expression.
  31.  
  32.     [ <precedence 0 <basicExpression>>:e / also ]+  ->  <makeProgn :e>;
  33.  
  34.  
  35. basicExpression =
  36.     ~ basic expressions are where most of the syntax in Mlisp appears
  37.  
  38.     begin  <blockDeclarations>:d  <expressions ';>:e  end  ->
  39.         (prog :d ::e),
  40.  
  41.     if  <expression>:p  then  <condClause :p>:c1  ->
  42.         (cond :c1),
  43.  
  44.     if  <expression>:p  then  <condClause :p>:c1  else  <condClause t>:c2  ->
  45.         (cond :c1 :c2),
  46.  
  47.     if  <expression>:p  then  <condClause :p>:c1  else  <condClause t>
  48.             ('t ('cond ...))  ->
  49.         (cond :c1 ...),
  50.  
  51.     return  <expression>:e  ->
  52.         (return :e),
  53.  
  54.     do  <expression>:e  [until | while]  <expression>:p  ->
  55.         (do (&v)
  56.             (nil)
  57.             (setq &v :e)
  58.             (cond ([:p | (not :p)] (return &v)))),
  59.  
  60.     collect  <expression>:e  [until | while]  <expression>:p  ->
  61.         (do (&v)
  62.             (nil)
  63.             (setq &v (<collectFunction :e> &v :e))
  64.             (cond ([:p | (not :p)] (return &v)))),
  65.  
  66.     until  <expression>:p  [do | collect]  <expression>:e  ->
  67.         (do (&v)
  68.             (:p (return &v))
  69.             (setq &v [:e | (<collectFunction :e> &v :e)])),
  70.  
  71.     while  <expression>:p  [do | collect]  <expression>:e  ->
  72.         (do (&v)
  73.             ((not :p) (return &v))
  74.             (setq &v [:e | (<collectFunction :e> &v :e)])),
  75.  
  76.     for  <forClauses for>:fl  [do | collect]  <expression>:e
  77.             [ until <expression>:p | while <expression>:p | ]  ->
  78.         <translateFor :fl  [prog2 | <collectFunction :e>]  :e
  79.             [:p | (not :p) | nil] >,
  80.  
  81.     lambda  <lambdaBody lambda>:lam  [ ';  '\(  <arguments>:args  ') ]  ->
  82.         [(:lam ::args) | :lam],
  83.  
  84.     let    <lambdaBody let>:l    ->  :l,
  85.  
  86.     let\*  <lambdaBody let\*>:l    ->  :l,
  87.  
  88.     defun  <nonReservedWord>:name  <checkFunction :name>  <lambdaBody lambda>
  89.             (lambda ...)  ->
  90.         (defun :name ...),
  91.  
  92.     defmacro  <nonReservedWord>:name  <checkFunction :name>  <lambdaBody lambda>
  93.             (lambda ...)  ->
  94.         (defmacro :name ...),
  95.  
  96.     defobfun  <nonReservedWord>:name  '\(  <identifier>:obj  ')
  97.             <checkFunction (:name :obj)>  <lambdaBody lambda> (lambda ...) ->
  98.         (defobfun (:name :obj) ...),
  99.  
  100.     case  <caseBody case>:c            ->  :c,
  101.  
  102.     ccase  <caseBody ccase>:c        ->  :c,
  103.  
  104.     ecase  <caseBody ecase>:c        ->  :c,
  105.  
  106.     typecase  <caseBody typecase>:c        ->  :c,
  107.  
  108.     ctypecase  <caseBody ctypecase>:c    ->  :c,
  109.  
  110.     etypecase  <caseBody etypecase>:c    ->  :c,
  111.  
  112.     global  <globalVariables>:vars        ->  :vars,
  113.  
  114.     constant  <aConstant>:const        ->  :const,
  115.  
  116. ~    define ...,
  117.  
  118.     ~ generic expressions, e.g. null foo(x,y,z).bar
  119.     <prefixes>:p  <primitive>  <qualifiers>:q  ->  <composition :p :q>;
  120.  
  121.  
  122. primitive =
  123.     <nonReservedWord>        ->  ,            ~ x
  124.  
  125.     ''  :sexp            ->  (quote :sexp),    ~ '(a b c)
  126.  
  127.     '\(  <expression>:e  ')        ->  :e,            ~ (x := y + z)
  128.  
  129.     '{  <expressions ',>:e  '}    ->  (list ::e),        ~ {x, y, z}
  130.  
  131.     ':  <identifier>:id  <pVariable :id t>:var
  132.                     ->  (vEval :var),    ~ :x
  133.  
  134.     :x  {if not symbolp(:x) :failMessage "anything but a symbol"}
  135.                     ->  :x;            ~ all other data types
  136.  
  137.  
  138. qualifiers =
  139.     :x  ->  :x,                        ~ x
  140.  
  141.     :x  '\(  <arguments>:args  ')  ->            ~ foo(x, y, z)
  142.         <qualifiers (:x ::args) >,
  143.  
  144.     :x  '[  <expressions ',>:args  ']  ->            ~ foo[x, y, z]
  145.         <qualifiers <translateIndex :x :args>>,
  146.  
  147.     :x  '.  [<identifier> | <primitive>]  :y  ->        ~ x.y  or  x.(y)
  148.         <qualifiers (get :x [(quote :y) | :y]) >,
  149.  
  150.     :x  ':=  <simpleExpression>:e  ->            ~ x := y, x(y) := z,
  151.         (setf :x :e);                    ~ x[y] := z, or x.y := z
  152.  
  153.  
  154. simpleExpression =
  155.     ~ a simple expression is the same as an expression except that it doesn't allow
  156.     ~ "also" to be included.  By convention in Mlisp, a <simpleExpression> always
  157.     ~ occurs on the right of the assignment operator (:=).
  158.  
  159.     <precedence 0 <basicExpression>>  ->  ;
  160.  
  161.  
  162. blockDeclarations =
  163.     [ <blockDeclaration>:d  '; ]*  ->  ( [::d]* );
  164.  
  165.  
  166. blockDeclaration =
  167.     new  <variables nil>:vars  ->  :vars;
  168.  
  169.  
  170. lambdaBody =
  171.     :lam  '\(  <variables t>:vars  ')  '=  <expression>:e  ->
  172.         (:lam :vars :e),
  173.  
  174.     :lam  '\(  <variables t>:vars  ')  '=  <expression>('progn ...)  ->
  175.         (:lam :vars ...);
  176.  
  177.  
  178. condClause =
  179.     :p  <expression>:e        ->  (:p :e),
  180.  
  181.     :p  <expression>('progn ...)    ->  (:p ...);
  182.  
  183.  
  184. forClauses =
  185.     [ <forClause>:f ]*  ->  :f;
  186.  
  187.  
  188. forClause =
  189.     for  <nonReservedWord>:var  [in | on]  <expression>:e  ->
  190.         (:var  [in | on]  :e),
  191.  
  192.     for  <nonReservedWord>:var  ':=  <simpleExpression>:from
  193.             to  <expression>:to  [by  <expression>:by]  ->
  194.         (:var  ':=  :from  :to  [:by | 1]);
  195.  
  196.  
  197. translateFor =
  198.     :clauses  :fn  :ex  ['nil | :be]=:b  ->
  199.         (do ( [<forVariable :clauses>]*  &v )
  200.             ( <forStopTest (or [<forStop :clauses>]*)>  &v )
  201.             [<setForVariable :clauses>]*
  202.             <setForValue :ex :fn>
  203.             [ | (if :be (return &v)) ]=:b );
  204.  
  205.  
  206. forVariable =
  207.     (:var  in  :e)            ->  {do :var2 := intern("&" cat :var cat "&")}
  208.                         :var  (:var2 :e (cdr :var2)),
  209.  
  210.     (:var  on  :e)            ->  (:var :e (cdr :var)),
  211.  
  212.     (:var  ':=  :min  :max  :step)    ->  <<numericForVariable :var :min :max :step>>;
  213.  
  214.  
  215. forStop =
  216.     (:var  in  :e)            ->  (atom {value intern("&" cat :var cat "&")}),
  217.  
  218.     (:var  on  :e)            ->  (atom :var),
  219.  
  220.     (:var  ':=  :min  :max  :step)    ->  <<numericForStopTest :var :max :step>>;
  221.  
  222.  
  223. forStopTest =
  224.     ('or :test)    ->  :test,    ~ optimization for single tests
  225.  
  226.     :test        ->  :test;
  227.         
  228.  
  229. setForVariable =
  230.     (:var  in  :e)    ->  (setq :var (car {value intern("&" cat :var cat "&")})),
  231.  
  232.     :clause        ->  ;
  233.  
  234.  
  235. setForValue =
  236.     :e  :fn        ->  (setq &v (:fn &v :e)),
  237.  
  238.     :e  'prog2    ->  (setq &v :e),
  239.  
  240.     'nil :fn    ->  ;
  241.  
  242.  
  243. collectFunction =
  244.     ('list ...)    ->  nconc,
  245.  
  246.     :ex        ->  append;
  247.  
  248.  
  249. caseBody =
  250.     :case  <expression>:e  of  begin  [ <caseClause>:c  '; ]*  end  ->
  251.         (:case :e ::c);
  252.  
  253.  
  254. caseClause =
  255.     :key  ':  <expression>:e        ->  (:key :e),
  256.  
  257.     :key  ':  <expression>('progn ...)    ->  (:key ...);
  258.  
  259.  
  260. globalVariables =
  261.     <nonReservedWord>:var  [':=  <simpleExpression>:e]  [',]  ->
  262.         (proclaim (quote (special :var)))  [';  (setq :var :e)]  [';  global];
  263.  
  264.  
  265. variables =
  266.     't    [ [<modifier>]  <aVariable>:vars / ', ]*    ->  :vars,
  267.  
  268.     'nil  [ <aVariable>:vars / ', ]*        ->  :vars;
  269.  
  270.  
  271. modifier =
  272.     ~ system keywords such as &optional and &rest are allowed only in the formal
  273.     ~ variable lists of function definitions and lambdas
  274.  
  275.     :word  {if member(:word, `lambda-list-keywords, :test `#'eq)}  ->  :word  ', ;
  276.  
  277.  
  278. aVariable =
  279.     <nonReservedWord>:v                ->  :v,        ~ x
  280.  
  281.     <nonReservedWord>:v  ':=  <simpleExpression>:e    ->  (:v :e),    ~ x := y
  282.  
  283.     <aKeyword>:key  <nonReservedWord>:v        ->  (:key :v),    ~ :key x
  284.  
  285.     <aKeyword>:key  <nonReservedWord>:v  ':=            ~ :key x := y
  286.         <simpleExpression>:e            ->  ((:key :v) :e);
  287.  
  288.  
  289. aKeyword =
  290.     ':  <identifier>:id  ->  <makeKeyword :id>;
  291.  
  292.  
  293. expressions =
  294.     ';  [ <expression>:e  '; ]*    ->  :e,
  295.  
  296.     ',  [ <expression>:e / ', ]*    ->  :e;
  297.  
  298.  
  299. arguments =
  300.     ~ translates the arguments to a function call; e.g. foo(x, y, :pretty t).
  301.     ~ it is not intended to be used for any other purpose
  302.  
  303.     [ <argument>:a / ', ]*  ->  :a;
  304.  
  305.  
  306. argument =
  307.     ~ handles keyword/argument pairs in function calls, e.g. foo(a, b, :pretty t)
  308.  
  309.     ':  <identifier>:key  <expression>:e  {if peek() member '(\, \))}  ->
  310.         <makeKeyword :key>  ',  :e,
  311.  
  312.     <expression>:e  ->  :e;
  313.  
  314.  
  315. aConstant =
  316.     <nonReservedWord>:id  ':=  <simpleExpression>:e  [',]  ->
  317.         (defconstant :id :e)  [';  constant];
  318.  
  319.  
  320. braceExpression =
  321.     ~ when Mlisp is loaded, allow Mlisp expressions in addition to Lisp expressions
  322.     ~ inside of Plisp braces { }; e.g allow either
  323.     ~    {do `(< x y)}     or     {do x < y}
  324.  
  325.     <sourceLanguage Mlisp>  <expression>:e  <sourceLanguage Plisp>  ->  :e;
  326.  
  327.  
  328. mlispFunction =
  329.     ~ for use by 'reparse'
  330.  
  331.     <sourceLanguage Mlisp>  <expression>:e  ';  ->  :e;
  332.  
  333.  
  334. ~---------------------------------------------------------------------------------------~
  335. ~                A few support routines                    ~
  336. ~---------------------------------------------------------------------------------------~
  337.  
  338. -Mlisp-
  339.  
  340. defun prefixes (&aux token := peek()) =
  341.     ~ checks if the next input token is an Mlisp prefix function (a one-argument
  342.     ~ function having the property glisp::prefix).
  343.     ~ such functions may be used without parentheses around their argument.
  344.  
  345.     if symbolp(token) and token.prefix then    ~ it's a prefix
  346.         next() also            ~ skip over it
  347.         if peek() eq !lparen then    ~ put it back; call has parens: fn(arg)
  348.             !source := {token} xPrepend !source also
  349.             nil
  350.         else token cons prefixes()    ~ check for more prefixes
  351.     else nil;
  352.  
  353.  
  354. defun precedence (rbp, e, &aux op := peek()) =
  355.     ~ this is where the precedence of infix operators controls the parse.
  356.     ~ operator precedence is determined by their left and right "binding powers".
  357.     ~ an operator with a higher right binding power has precedence over an operator
  358.     ~ with a lower left binding power.  All binding powers are > 0.
  359.     ~ 'op' is the next infix operator, if any, in the input.
  360.  
  361.     if not symbolp(op) then            ~ make sure it's a symbol
  362.         failure("a symbol")
  363.     else if rbp > bindingPower(op,'left) then  ~ stronger right binding power
  364.         e                ~ e.g.  a * b + c  (where op is +)
  365.     else next() also            ~ stronger left binding power
  366.         precedence(rbp, compose(op, e,    ~ e.g.  a + b * c  (where op is *)
  367.             precedence(bindingPower(op,'right), pcall('basicExpression, nil))));
  368.  
  369.  
  370. defun bindingPower (op, ind) =
  371.     ~ computes the binding power of infix operators
  372.  
  373.     op.(ind)                ~ operator has the specified indicator
  374.         or (op.mlisp and -1)        ~ or is an Mlisp reserved word
  375.         or (op.delimiter and -1)    ~ or is a delimiter
  376.         or 'default.(ind);        ~ otherwise use the default value
  377.  
  378.  
  379. defun compose (fn, e1, e2) =
  380.     ~ :fn  {if :fn.associative}  (:fn ...)  (:fn ...)    ->  (:fn ... ...)
  381.     ~ :fn  {if :fn.associative}  (:fn ...)  :e2        ->  (:fn ... :e2)
  382.     ~ :fn  {if :fn.associative}  :e1  (:fn ...)        ->  (:fn :e1 ...)
  383.     ~ :fn  :e1  :e2                        ->  (:fn :e1 :e2)
  384.  
  385.     if not fn.associative then {fn, e1, e2}
  386.     else if consp(e1) and car(e1) eq fn then
  387.         if consp(e2) and car(e2) eq fn then e1 append cdr(e2)
  388.         else e1 append {e2}
  389.     else if consp(e2) and car(e2) eq fn then fn cons e1 cons cdr(e2)
  390.     else {fn, e1, e2};
  391.  
  392.  
  393. defun composition (fns, ex) =
  394.     ~ (f g ...) x -> (f (g (... x)))
  395.  
  396.     if null fns then ex
  397.     else {car fns, composition(cdr fns, ex)};
  398.  
  399.  
  400. defun makeKeyword (id) =
  401.     ~ makes id a keyword in the Keyword package
  402.  
  403.     intern(`symbol-name(id), 'keyword);
  404.  
  405.  
  406. defun makeProgn (l) =
  407.     ~ translates a list of expressions (e1 e2 ...) -> (progn e1 e2 ...)
  408.     ~ and a single expression (e1) -> e1
  409.  
  410.     if null cdr(l) then car(l)
  411.     else 'progn cons l;
  412.  
  413.  
  414. defun translateIndex (ex, l) =
  415.     ~ translates x[n] -> (nth (- n 1) x); optimizes when n is an explicit integer
  416.  
  417.     if null l then ex
  418.     else if integerp(car(l)) then translateIndex(numericIndex(car l, ex), cdr l)
  419.     else translateIndex({'nth, {'\-, car l, 1}, ex}, cdr l);
  420.  
  421.  
  422. defun numericIndex (n, ex) =
  423.     if n < 1 then ex
  424.     else if n > 10 then {'nth, n-1, ex}
  425.     else {'(car cadr caddr cadddr fifth sixth seventh eighth ninth tenth)[n], ex};
  426.  
  427.  
  428. defun numericForVariable (var, min, max, step) =
  429.     begin
  430.     new max2  := if not numberp(max)  then intern("&"  cat var cat "&" ) else nil;
  431.     new step2 := if not numberp(step) then intern("&&" cat var cat "&&") else nil;
  432.     return    {{var, min, {'\+, var, step2 or step}}}
  433.             append (max2  and {{max2,  max }})
  434.             append (step2 and {{step2, step}});
  435.     end;
  436.  
  437.  
  438. defun numericForStopTest (var, max, step) =
  439.     begin
  440.     if not numberp(max)  then max  := intern("&"  cat var cat "&" );
  441.     if not numberp(step) then step := intern("&&" cat var cat "&&");
  442.     return    if not numberp(step) then
  443.             { {'and, {'\>, step, 0}, {'\>, var, max}},
  444.               {'and, {'\<, step, 0}, {'\<, var, max}},
  445.               {'and, {'\=, step, 0},
  446.                     '(error "increment = 0 in Mlisp FOR loop")} }
  447.         else if step > 0 then {{'\>, var, max}}
  448.         else if step < 0 then {{'\<, var, max}}
  449.         else pError("increment = 0 in FOR loop");
  450.     end;
  451.  
  452.  
  453. defun reparseMlisp (name, filename, &key target := nil, package := nil) =
  454.     ~ supplies the proper arguments to 'reparse' for parsing an Mlisp function
  455.  
  456.     reparse(name, filename, :source 'Mlisp, :target target,
  457.         :parser 'mlispFunction, :locater 'locateMlispFunction,
  458.         :readtable `*glisp-readtable*, :package package);
  459.  
  460.  
  461. defun locateMlispFunction (name, stream, `*readtable*) =
  462.     ~ quickly skips to the beginning of an Mlisp function; works only on file streams
  463.  
  464.     begin
  465.     new x := '\;, index, foundit;
  466.     until (x eq '\; or x eq '\- or x eq !eof)
  467.         and case x of
  468.             begin
  469.             \; :                ~ ; defun name ...
  470.                 begin
  471.                 index := `file-position(stream);
  472.                 foundit :=  read(stream, nil, !eof, nil) member
  473.                         '(defun defmacro defobfun)
  474.                     and read(stream, nil, !eof, nil) eq name;
  475.                 `file-position(stream, index);
  476.                 return foundit;
  477.                 end;
  478.             \- :                ~ -Mlisp- name = ...
  479.                 begin
  480.                 index := `file-position(stream);
  481.                 foundit :=  read(stream, nil, !eof, nil) eq 'Mlisp
  482.                     and read(stream, nil, !eof, nil) eq '\-
  483.                     and (index := `file-position(stream))
  484.                     and read(stream, nil, !eof, nil) member
  485.                         '(defun defmacro defobfun)
  486.                     and read(stream, nil, !eof, nil) eq name;
  487.                 `file-position(stream, index);
  488.                 return foundit;
  489.                 end;
  490.             otherwise:            ~ end of file
  491.                 t;
  492.             end
  493.     do x := read(stream, nil, !eof, nil);
  494.     return x neq !eof;
  495.     end;
  496.